<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/model/DAO/mysql/filters/EntityIdentityFilter.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/model/DAO/mysql/filters/DepartmentPersonFilter.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/model/DAO/mysql/filters/DepartmentTypeFilter.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/model/DAO/mysql/filters/Filter.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/model/DAO/DepartmentDAO.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/entities/Entity.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/entities/Department.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/entities/Employee.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/entities/DepartmentType.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/utils/Str.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/exceptions/DataBaseException.php';

/**
 * Класс для работы со структурными подразделениями в БД
 */
class DepartmentDAOImpl extends DepartmentDAO {

	/**
	 * Метод, для создания новой записи структурного подразделения в БД
	 */
	public function create(Entity $department) {
		/*		$sql = 'INSERT INTO `department` (`name`';
		 if($department->getParent() !== null) {
				$sql .= ',`id_parent`';
				}
				$sql .= ',`id_department_type`'
				if($department->getHead() !== null) {
				$sql .= ',`id_employee`';
				}
				$sql .= ') VALUES ("'.$department->getName().'"';
						if($department->getParent() !== null) {
						$sql .= ','.$department->getParent()->getIdentity();
						}
						$sql .= ','.$department->getType()->getIdentity();
						if($department->getHead() !== null) {
						$sql .= ','.$department->getHead()->getIdentity();
						}
						$sql .= ')';
		$this->query($sql);
		$department->setIdentity($this->identity());
		return $department;
		*/

		$sql = 'INSERT INTO `department` (`name`, `id_department_type`) VALUES(?, ?)';
		if($department->getParent() !== null) {
			$sql = 'INSERT INTO `department` (`name`, `id_parent`, `id_department_type`) VALUES(?, ?, ?)';
			if($department->getHead() !== null) {
				$sql = 'INSERT INTO `department` (`name`, `id_parent`, `id_department_type`, `id_employee`) VALUES(?, ?, ?, ?)';
			}
		} elseif ($department->getHead() !== null) {
			$sql = 'INSERT INTO `department` (`name`, `id_department_type`, `id_employee`) VALUES(?, ?, ?)';
		}

		$name = $department->getName();
		$departmentTypeId = $department->getType()->getIdentity();
		$parentId = $department->getParent()->getIdentity();
		$employeeId = $department->getHead()->getIdentity();

		$stmt = $this->dbh->connection->prepare($sql);
		$stmt->bindValue(1, $name);
		$stmt->bindValue(2, $departmentTypeId);

		if($department->getParent() !== null) {
			$stmt->bindValue(1, $name);
			$stmt->bindValue(2, $parentId);
			$stmt->bindValue(3, $departmentTypeId);

			if($department->getHead() !== null) {
				$stmt->bindValue(1, $name);
				$stmt->bindValue(2, $parentId);
				$stmt->bindValue(3, $departmentTypeId);
				$stmt->bindValue(4, $employeeId);
			}
		} elseif ($department->getHead() !== null) {
			$stmt->bindValue(1, $name);
			$stmt->bindValue(2, $departmentTypeId);
			$stmt->bindValue(3, $employeeId);
		}

		try {
			$this->dbh->query($stmt);
			$department->setIdentity($this->dbh->identity());
			return $department;
		} catch(PDOException $excepton) {
			return null;
		}

	}

	/**
	 * Метод, отвечающий за поиск структурного подразделения в БД
	 */
	private function findDepartment($departments, Filter $filter) {
		$result = array();
		foreach($departments as $department) {
			if($filter->apply($department)) {
				$result[] = $department;
			}
			$children = $this->findDepartment($department->getChildren(), $filter);
			foreach($children as $child) {
				$result[] = $child;
			}
		}
		return $result;
	}

	/**
	 * Метод, отвечающий за поиск по узаканному типу структурного подразделения в БД
	 */
	public function findByType(DepartmentType $type) {
		$filter = new DepartmentTypeFilter($type);
		return $this->findDepartment($this->getAll(), $filter);
	}

	public function findByHead(Person $head) {
		$filter = new DepartmentPersonFilter($head);
		return $this->findDepartment($this->getAll(), $filter);
	}

	/**
	 * Метод, получающий запись со структурным подразделенем из БД
	 */
	public function read($identity) {
		$filter = new EntityIdentityFilter($identity);
		$departments = $this->findDepartment($this->getAll(), $filter);
		if(count($departments) == 1) {
			return $departments[0];
		}
		return null;
	}

	/**
	 * Метод, отвечающий за обновление запись структурного подразделения в БД
	 */
	public function update(Entity $department) {
		/*		$sql = 'UPDATE `department` ';
		 $sql .= 'SET `name`="'.$department->getName().'"';
		if($department->getParent() !== null) {
		$sql .= ',`id_parent`='.$department->getParent()->getIdentity();
		} else {
		$sql .= ',`id_parent`=NULL';
		}
		$sql .= ',`id_department_type`='.$department->getType()->getIdentity();
		if($department->getHead() !== null) {
		$sql .= ',`id_employee`='.$department->getHead()->getIdentity();
		} else {
		$sql .= ',`id_employee`=NULL';
		}
		$sql .= ' WHERE `id`='.$department->getIdentity();
		$this->query($sql);
		return $department;
		*/

		$sql = 'UPDATE `department` SET `name`=?, `id_parent`=NULL, `id_department_type`=?, `id_employee`=NULL WHERE `id`=?';
		if($department->getParent() !== null) {
			if($department->getHead() !== null) {
				$sql = 'UPDATE `department` SET `name`=?, `id_parent=?, `id_department_type`=?, `id_employee`=? WHERE `id`=?';
			} else {
				'UPDATE `department` SET `name`=?, `id_parent`=?, `id_department_type`=?, `id_employee`=NULL WHERE `id`=?';
			}
		} elseif ($department->getHead() !== null) {
			$sql = 'UPDATE `department` SET `name`=?, `id_parent`=NULL, `id_department_type`=?, `id_employee`=? WHERE `id`=?';
		}

		$name = $department->getName();
		$departmentTypeId = $department->getType()->getIdentity();
		$parentId = $department->getParent()->getIdentity();
		$employeeId = $department->getHead()->getIdentity();
		$id = $department->getIdentity();

		$stmt = $this->dbh->connection->prepare($sql);
		$stmt->bindValue(1, $name);
		$stmt->bindValue(2, $departmentTypeId);
		$stmt->bindValue(3, $id);

		if($department->getParent() !== null) {
			if($department->getHead() !== null) {
				$stmt->bindValue(1, $name);
				$stmt->bindValue(2, $parentId);
				$stmt->bindValue(3, $departmentTypeId);
				$stmt->bindValue(4, $employeeId);
				$stmt->bindValue(5, $id);
			} else {
				$stmt->bindValue(1, $name);
				$stmt->bindValue(2, $parentId);
				$stmt->bindValue(3, $departmentTypeId);
				$stmt->bindValue(4, $id);
			}
		} elseif ($department->getHead() !== null) {
			$stmt->bindValue(1, $name);
			$stmt->bindValue(2, $departmentTypeId);
			$stmt->bindValue(3, $employeeId);
			$stmt->bindValue(4, $id);
		}

		$this->dbh->query($stmt);
		return $department;

	}

	/**
	 * Метод, удаляющий запись структурного подразделения из БД
	 */
	public function delete($identity) {
		/*			$sql = 'DELETE FROM `department` ';
			$sql .= 'WHERE `id`='.$identity;
		try {
		$this->query($sql);
		return true;
		} catch(DataBaseException $exception) {
		return false;
		}
		*/

		$id = (int)($identity);

		$stmt = $this->dbh->connection->prepare('DELETE FROM `department` WHERE `id`=?');
		$stmt->bindValue(1, $id);

		try {
			$this->dbh->query($stmt);
			return true;
		} catch (PDOException $exception) {
			return false;
		}

	}

	/**
	 * Метод, получающий все запись структурных подразделений из БД по правилам
	 */
	public function getAll() {
		/*		$service = getService('DepartmentTypeService'); // Почему DAO использует  сервис ?????????
		 $departmentTypes = $service->getAll();
		$departmentTypeMap = array();
		foreach($departmentTypes as $departmentType) {
		$departmentTypeMap[$departmentType->getIdentity()] = $departmentType;
		}
		$service = getService('EmployeeService');
		$sql = 'SELECT `id`,`name`,`id_parent`,`id_department_type`,`id_employee` ';
		$sql .= 'FROM `department`';
		$this->query($sql);
		$allDepartments = array();
		while($row = $this->row()) {
		$department = new Department();
		$department->setIdentity($row['id']);
		$department->setName($row['name']);
		if(Str::isNotEmpty($row['id_parent'])) {
		$parent = new Department();
		$parent->setIdentity($row['id_parent']);
		$department->setParent($parent);
		}
		$department->setType($departmentTypeMap[$row['id_department_type']]);
		if(Str::isNotEmpty($row['id_employee'])) {
		$head = new Employee();
		$head->setIdentity($row['id_employee']);
		$department->setHead($head);
		}
		$allDepartments[$department->getIdentity()] = $department;
		}
		$this->close();
		foreach($allDepartments as $department) {
		$head = $department->getHead();
		if($head !== null) {
		$headIdentity = $head->getIdentity();
		$head = $service->read($headIdentity);
		$department->setHead($head);
		}
		$parent = $department->getParent();
		if($parent !== null) {
		$parentIdentity = $parent->getIdentity();
		$parent = $allDepartments[$parentIdentity];
		$department->setParent($parent);
		}
		}
		$departments = array();
		foreach($allDepartments as $department) {
		$parent = $department->getParent();
		if($parent !== null) {
		$parent->addChild($department);
		} else {
		$departments[] = $department;
		}
		}
		return $departments;
		*/

		$stmt = $this->dbh->connection->prepare('SELECT `id`, `name`, `id_parent`, `id_department_type`, `id_employee` FROM `department`');
		$this->dbh->query($stmt);
		$allDepartments = array();
		while($row = $this->dbh->row()) {
			$department = new Department();
			$department->setIdentity($row['id']);
			$department->setName($row['name']);
			if(Str::isNotEmpty($row['id_parent'])) {
				// В родительское структ.подразд. заносим только стр.подразд. с заполненным id
				$parent = new Department();
				$parent->setIdentity($row['id_parent']);
				$department->setParent($parent);
			}
			if(Str::isNotEmpty($row['id_department_type'])) {
				$depType = new DepartmentType();
				$depType->setIdentity($row['id_department_type']);
				$department->setType($depType);
			}
			if(Str::isNotEmpty($row['id_employee'])) {
				$head = new Employee();
				$head->setIdentity($row['id_employee']);
				$department->setHead($head);
			}
			$allDepartments[$department->getIdentity()] = $department;
		}
		// Заполняем родительские структурные подразделения
		foreach($allDepartments as $department){
			$parent = $department->getParent();
			if($parent !== null) {
				$parentIdentity = $parent->getIdentity();
				$parent = $allDepartments[$parentIdentity];
				$department->setParent($parent);// Здесь родительское структ.подразд. уже со всеми заполненными полями
			}
		}

		$this->dbh->close();

		$departments = array();
		foreach($allDepartments as $department) {
			$parent = $department->getParent();
			if($parent !== null) {
				$parent->addChild($department);
			} else {
				$departments[] = $department;
			}
		}
		return $departments;
	}

}
?>